package tools

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"mime/multipart"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	. "github.com/hunterhug/go_image"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
)

/*
 +----------------------------------------------------------------------
 + Title        : minio 分布式文件存储
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2021-09-22
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : minio
 +----------------------------------------------------------------------
*/
// 定义MinioImageUpload结构体
type MinioImageUpload struct {
	minioClient *minio.Client
	bucket      string
}

var client *minio.Client

// MINIO配置结构体
type MinioConf struct {
	EndPoint        string `yaml:"endpoint" json:"endpoint"`
	AccessKeyId     string `yaml:"access_key_id" json:"access_key_id"`
	AccessKeySecret string `yaml:"access_key_secret" json:"access_key_secret"`
	AseSsl          bool   `yaml:"use_ssl" json:"use_ssl"`
	Bucket          string `yaml:"bucket" json:"bucket"`
}

/**
 * 创建MinioImageUpload
 *
 * @return *MinioImageUpload, error
 * @author huwl
 */
func NewMinioImageUpload() (*MinioImageUpload, error) {
	var err error
	// 本地配置
	// cfg, err := GetConfig("minio", "yml")
	// if err != nil {
	// 	return nil, err
	// }

	// 创建MINIO连接
	// client, err := minio.New(cfg.GetString(Env+".endpoint"), &minio.Options{
	// 	Creds:  credentials.NewStaticV4(cfg.GetString(Env+".access_key_id"), cfg.GetString(Env+".access_key_secret"), ""),
	// 	Secure: cfg.GetBool(Env + ".use_ssl"),
	// })

	// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// ++++++++++++       配置中心模式,读取配置中心的minio配置数据     ++++++++++++
	// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	minioConf := &MinioConf{}
	InitConfigCenter(MinioConfigCenter, minioConf)

	// 创建MINIO连接
	if client == nil {
		client, err = minio.New(minioConf.EndPoint, &minio.Options{
			Creds:  credentials.NewStaticV4(minioConf.AccessKeyId, minioConf.AccessKeySecret, ""),
			Secure: minioConf.AseSsl,
		})
		if err != nil {
			return nil, err
		}
	}

	return &MinioImageUpload{
		minioClient: client,
		// bucket:      cfg.GetString(Env + ".bucket"),
		bucket: minioConf.Bucket,
	}, nil
}

/**
 * 上传单张图片
 *
 * @param *gin.Context ctx --------------------------------------------必传
 * @param *multipart.FileHeader image ---------------------------------必传
 * @param []map[string]string thumbs ----------------------------------非必传
 * @param map[string]string water -------------------------------------非必传
 * @return map[string]interface{}, error
 */
func (m *MinioImageUpload) MinioSingleUploadImage(ctx *gin.Context, image *multipart.FileHeader, thumbs []map[string]string, water map[string]string) (map[string]interface{}, error) {
	imageExt := path.Ext(image.Filename)
	allowExtMap := map[string]bool{
		".jpg":  true,
		".png":  true,
		".gif":  true,
		".jepg": true,
	}

	if !allowExtMap[imageExt] {
		return nil, errors.New("图片类型错误仅支持jpg/png/gif/jepg")
	}

	filepath := "./static/upload_images/" + GetDay()
	err := os.MkdirAll(filepath, 0755)
	if err != nil {
		return nil, errors.New("创建目录失败")
	}

	filename := strconv.FormatInt(GetUnix(), 10)
	h := md5.New()
	h.Write([]byte(filename)) // 需要加密的字符串
	filename = hex.EncodeToString(h.Sum(nil)) + imageExt
	imagePath := filepath + "/" + filename

	// 上传文件到指定的路径
	err = ctx.SaveUploadedFile(image, imagePath)
	if err != nil {
		return nil, errors.New("上传图片失败")
	}

	thumbUrls := []map[string]string{}
	if len(thumbs) > 0 {
		for _, thumb := range thumbs {
			imageUrl := filepath + "/thumb-" + thumb["width"] + "X" + thumb["height"] + filename
			width, _ := strconv.Atoi(thumb["width"])
			height, _ := strconv.Atoi(thumb["height"])
			err = ThumbnailF2F(imagePath, imageUrl, width, height)
			if err != nil {
				return nil, err
			}

			thumbUrl := map[string]string{}
			thumbUrl["image_url"] = strings.TrimLeft(imageUrl, ".")
			thumbUrl["absolute_image_url"] = UploadImageDomain + strings.TrimLeft(imageUrl, ".")

			thumbUrls = append(thumbUrls, thumbUrl)
		}
	}

	// 判断bucket是否存在
	bucketExists, err := m.minioClient.BucketExists(ctx, m.bucket)
	if err != nil {
		os.Remove(imagePath)
		return nil, err
	}
	if !bucketExists {
		os.Remove(imagePath)
		return nil, errors.New("bucket 不存在，请创建")
	}

	// 上传图片到 minio
	_, err = m.minioClient.FPutObject(ctx, m.bucket, filename, imagePath, minio.PutObjectOptions{})
	if err != nil {
		os.Remove(imagePath)
		return nil, err
	}

	return map[string]interface{}{
		"image_url":          strings.TrimLeft(imagePath, "."),
		"absolute_image_url": UploadImageDomain + strings.TrimLeft(imagePath, "."),
		"thumb_urls":         thumbUrls,
	}, nil
}
